package cloud

import (
	"context"
	"encoding/json"
	"fmt"
	"math/rand"
	"net/http"
	"strconv"
	"strings"
	"sync"
	"time"

	"gitee.com/rw555/fdsmastergo/pkg/config"
	"gitee.com/rw555/fdsmastergo/pkg/logger"
	"go.uber.org/zap"
)

// ResponseMessage 响应消息结构
type ResponseMessage struct {
	Topic   string
	Result  int
	Message string
}

// Publisher MQTT消息发布器
type Publisher struct {
	configClient   *config.Client
	connMgr        *ConnectionManager
	wg             sync.WaitGroup
	stopChan       chan struct{}
	responseChan   chan *ResponseMessage
	publishCounter int
}

// NewPublisher 创建消息发布器
func NewPublisher(connMgr *ConnectionManager, configClient *config.Client) *Publisher {
	rand.Seed(time.Now().UnixNano())
	return &Publisher{
		configClient:   configClient,
		connMgr:        connMgr,
		stopChan:       make(chan struct{}),
		responseChan:   make(chan *ResponseMessage, 32), // 缓冲通道，避免阻塞
		publishCounter: 0,
	}
}

// Start 启动消息发布器
func (p *Publisher) Start(ctx context.Context) error {
	// 启动实时数据发布循环
	p.wg.Add(1)
	go p.publishLoop(ctx)

	logger.SystemInfo("消息发布器启动成功")
	return nil
}

// Stop 停止消息发布器
func (p *Publisher) Stop() {
	close(p.stopChan)
	p.wg.Wait()
	logger.SystemInfo("消息发布器已停止")
}

// PublishResponse 发送响应消息
func (p *Publisher) PublishResponse(topic string, result int, message string) {
	select {
	case p.responseChan <- &ResponseMessage{
		Topic:   topic,
		Result:  result,
		Message: message,
	}:
	default:
		logger.SystemError("响应消息队列已满，消息丢弃",
			zap.String("topic", topic),
			zap.Int("result", result))
	}
}

// publishLoop 实时数据发布循环
func (p *Publisher) publishLoop(ctx context.Context) {
	defer p.wg.Done()

	logger.SystemInfo("启动数据发布协程")
	ticker := time.NewTicker(5 * time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-ctx.Done():
			return
		case <-p.stopChan:
			return
		case <-ticker.C:
			p.publishRealData()
		case resp := <-p.responseChan:
			p.publishData(resp)
		}
	}
}

// publishData 发布应答消息
func (p *Publisher) publishData(resp *ResponseMessage) error {
	actualTopic := resp.Topic
	if strings.Contains(resp.Topic, "devices/command/response/{message_id}") { // 发布事件数据
		messageID := strconv.FormatInt(time.Now().UnixNano()/1e6%10000000, 10)
		actualTopic = strings.ReplaceAll(resp.Topic, "{message_id}", messageID)
		response := map[string]interface{}{
			"result":  resp.Result,
			"message": resp.Message,
			"ts":      time.Now().Unix(),
		}
		jsonData, err := json.Marshal(response)
		if err != nil {
			return fmt.Errorf("序列化事件数据失败: %w", err)
		}
		if err := p.connMgr.PublishMQTT(actualTopic, string(jsonData)); err != nil {
			logger.SystemError("MQTT事件发布失败", zap.String("topic", actualTopic), zap.Error(err))
		} else {
			logger.SystemInfo("发布应答事件", zap.Int("publishCounter", p.publishCounter), zap.String("topic", actualTopic))
		}
	} else if strings.Contains(resp.Topic, "devices/attributes/set/response/{message_id}") { // 发布事件数据
		messageID := strconv.FormatInt(time.Now().UnixNano()/1e6%10000000, 10)
		actualTopic = strings.ReplaceAll(resp.Topic, "{message_id}", messageID)
		response := map[string]interface{}{
			"result":  resp.Result,
			"message": resp.Message,
			"ts":      time.Now().Unix(),
		}
		jsonData, err := json.Marshal(response)
		if err != nil {
			return fmt.Errorf("序列化事件数据失败: %w", err)
		}
		if err := p.connMgr.PublishMQTT(actualTopic, string(jsonData)); err != nil {
			logger.SystemError("MQTT事件发布失败", zap.String("topic", actualTopic), zap.Error(err))
		} else {
			logger.SystemInfo("发布应答事件", zap.Int("publishCounter", p.publishCounter), zap.String("topic", actualTopic))
		}
	} else {
		logger.SystemError("未知消息类型", zap.String("topic", actualTopic))
	}

	return nil
}

// publishRealData 发布实时数据
func (p *Publisher) publishRealData() error {
	// 生成随机数据
	temp := 230 + rand.Intn(50) // 230-280
	power := 80 + rand.Intn(20) // 80-100
	heater := "open"
	if rand.Float32() < 0.3 { // 30%概率关闭
		heater = "close"
	}
	pump := "open"
	if rand.Float32() < 0.2 { // 20%概率关闭
		pump = "close"
	}

	// 发布到所有配置的发布主题
	actualTopic := ""
	publishTopics := p.configClient.GetConfigsByPrefix(p.connMgr.systemConfig, "mqtt.publish.")
	if publishTopics == nil {
		return fmt.Errorf("发布主题配置格式错误")
	}

	for _, topicInterface := range publishTopics {
		topic, ok := topicInterface.(string)
		if !ok {
			logger.SystemError("发布主题格式错误", zap.Any("topic", topicInterface))
			continue
		}
		actualTopic = topic

		if strings.Contains(topic, "devices/telemetry") { // 更新遥测数据
			smokeDevices, err := p.getBluetoothSmokeDevices()
			if err != nil {
				logger.SystemError("获取烟感设备列表失败", zap.Error(err))
			}
			personnelDevices, err := p.getBluetoothPersonnelDevices()
			if err != nil {
				logger.SystemError("获取模拟人员设备列表失败", zap.Error(err))
			}
			data := map[string]interface{}{
				"temp":      strconv.Itoa(temp),
				"power":     strconv.Itoa(power),
				"heater":    heater,
				"pump":      pump,
				"smoke":     smokeDevices,
				"personnel": personnelDevices,
			}
			jsonData, err := json.Marshal(data)
			if err != nil {
				return fmt.Errorf("序列化数据失败: %w", err)
			}
			if err := p.connMgr.PublishMQTT(actualTopic, string(jsonData)); err != nil {
				logger.SystemError("MQTT发布失败", zap.String("topic", actualTopic), zap.Error(err))
			} else {
				logger.SystemDebug("发布主题", zap.Int("publishCounter", p.publishCounter), zap.String("topic", actualTopic))
			}
		} else if strings.Contains(topic, "devices/attributes/{message_id}") { // 更新属性数据
			if p.publishCounter%4 != 0 {
				continue
			}
			messageID := strconv.FormatInt(time.Now().UnixNano()/1e6%10000000, 10) // 生成消息标识符（毫秒时间戳的后七位）
			actualTopic = strings.ReplaceAll(topic, "{message_id}", messageID)
			data := map[string]interface{}{
				"duty_max": 100,
			}
			jsonData, err := json.Marshal(data)
			if err != nil {
				return fmt.Errorf("序列化数据失败: %w", err)
			}
			if err := p.connMgr.PublishMQTT(actualTopic, string(jsonData)); err != nil {
				logger.SystemError("MQTT发布失败", zap.String("topic", actualTopic), zap.Error(err))
			} else {
				logger.SystemDebug("发布主题", zap.Int("publishCounter", p.publishCounter), zap.String("topic", actualTopic))
			}
		} else if strings.Contains(topic, "devices/event/{message_id}") { // 发布事件数据
			if p.publishCounter%2 != 0 {
				continue
			}
			messageID := strconv.FormatInt(time.Now().UnixNano()/1e6%10000000, 10)
			actualTopic = strings.ReplaceAll(topic, "{message_id}", messageID)
			event := map[string]interface{}{
				"method": "TemperatureExceeded",
				"params": map[string]interface{}{
					"event_id":   messageID,
					"event_type": "HIGH_TEMPERATURE",
					"severity":   "WARNING",
					"timestamp":  time.Now().UnixMilli(),
					"data": map[string]interface{}{
						"temp":      temp,
						"threshold": 220,
					},
				},
			}
			jsonData, err := json.Marshal(event)
			if err != nil {
				return fmt.Errorf("序列化事件数据失败: %w", err)
			}
			if err := p.connMgr.PublishMQTT(actualTopic, string(jsonData)); err != nil {
				logger.SystemError("MQTT事件发布失败", zap.String("topic", actualTopic), zap.Error(err))
			} else {
				logger.SystemDebug("发布事件", zap.Int("publishCounter", p.publishCounter), zap.String("topic", actualTopic))
			}
		} else if strings.Contains(topic, "ota/devices/progress") { // 更新属性数据
			if p.publishCounter%3 != 0 {
				continue
			}
			actualTopic = topic
			data := map[string]interface{}{
				"step":   strconv.Itoa(power),
				"desc":   fmt.Sprintf("升级进度%d%%", power),
				"module": "rk3506img",
			}
			jsonData, err := json.Marshal(data)
			if err != nil {
				return fmt.Errorf("序列化数据失败: %w", err)
			}
			if err := p.connMgr.PublishMQTT(actualTopic, string(jsonData)); err != nil {
				logger.SystemError("MQTT发布失败", zap.String("topic", actualTopic), zap.Error(err))
			} else {
				logger.SystemDebug("发布主题", zap.Int("publishCounter", p.publishCounter), zap.String("topic", actualTopic))
			}
		} else {
			continue
		}
	}
	p.publishCounter++

	return nil
}

// getBluetoothSmokeDevices 从蓝牙服务获取烟感设备列表
func (p *Publisher) getBluetoothSmokeDevices() ([]map[string]interface{}, error) {
	// 发送HTTP请求获取设备列表
	resp, err := http.Get("http://localhost:8083/api/v1/devices/smoke")
	if err != nil {
		return nil, fmt.Errorf("请求蓝牙设备列表失败: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("获取蓝牙设备列表失败: 状态码 %d", resp.StatusCode)
	}

	var result struct {
		Devices []map[string]interface{} `json:"devices"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, fmt.Errorf("解析蓝牙设备列表失败: %w", err)
	}

	logger.SystemDebug("获取蓝牙设备列表成功", zap.Any("result", result))
	return result.Devices, nil
}

// getBluetoothPersonnelDevices 从蓝牙服务获取模拟人员设备列表
func (p *Publisher) getBluetoothPersonnelDevices() ([]map[string]interface{}, error) {
	// 发送HTTP请求获取设备列表
	resp, err := http.Get("http://localhost:8083/api/v1/devices/personnel")
	if err != nil {
		return nil, fmt.Errorf("请求蓝牙设备列表失败: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("获取蓝牙设备列表失败: 状态码 %d", resp.StatusCode)
	}

	var result struct {
		Devices []map[string]interface{} `json:"devices"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, fmt.Errorf("解析蓝牙设备列表失败: %w", err)
	}

	logger.SystemDebug("获取蓝牙设备列表成功", zap.Any("result", result))
	return result.Devices, nil
}
